#include "system_cmd.h"
#include "system.h"
#include "uart_peripheral.h"
#include "util_cmd.h"
#include "util_str.h"
#include "FreeRTOS.h"
#include "task.h"
#include "string.h"

static char * const sCmdSystem = "system";
static char * const sParName = "name";
static char * const sParVersion = "version";
static char * const sParGet = "get";
static char * const sPar2ndMemory = "memory";
static char * const sPar2ndClock = "clock";

static void parGetFunc(uint8_t *data, uint16_t len)
{
	uint8_t *p1 = NULL;
	
	int16_t index;
	SYSTEM_CLK_SORCE_E source;
	
	index = StrGetCHIndex((char *)data, '-');
	if (index == -1) {
		index = StrGetNextNotSpace((char *)data);
		/* system -get */
		if (index == -1) {
			UartPutsDMA(UART_COM0, "system -get: No param\r\n");
		}
		else {
			/* system -get memory */
			if (strncmp((char *)&data[index], sPar2ndMemory, 6) == 0) {
				taskENTER_CRITICAL();
				
				UartPrintf(UART_COM0, "Total space: %d Bytes\r\n", configTOTAL_HEAP_SIZE);
				UartPrintf(UART_COM0, "Current free space: %d Bytes\r\n", xPortGetFreeHeapSize());
				UartPrintf(UART_COM0, "Historical minimum: %d Bytes\r\n", xPortGetMinimumEverFreeHeapSize());
				
				taskEXIT_CRITICAL();
			}
			/* system -get clock */
			else if (strncmp((char *)&data[index], sPar2ndClock, 5) == 0) {
				taskENTER_CRITICAL();
				
				UartPuts(UART_COM0, "System clock comefrom: ");
				source = SystemGetClkSource();
				if (source == SYSTEM_CLK_SOURCE_IRC8M) {
					UartPuts(UART_COM0, "IRC8M\r\n");
				}
				else if (source == SYSTEM_CLK_SOURCE_HXTAL) {
					UartPuts(UART_COM0, "HXTAL\r\n");
				}
				else if (source == SYSTEM_CLK_SOURCE_PLL) {
					UartPuts(UART_COM0, "PLL\r\n");
				}
				else {
					UartPuts(UART_COM0, "NULL\r\n");
				}
				
				p1 = (uint8_t *)pvPortMalloc(6);
				if (p1 == NULL) {
					UartPuts(UART_COM0, "system -get clock: Can't get memory\r\n");
					return;
				}
				
				p1[0] = SystemGetClkFreq(SYSTEM_CLK_SYS, SYSTEM_CLK_UNIT_MHZ);
				p1[1] = SystemGetClkFreq(SYSTEM_CLK_AHB, SYSTEM_CLK_UNIT_MHZ);
				p1[2] = SystemGetClkFreq(SYSTEM_CLK_APB1, SYSTEM_CLK_UNIT_MHZ);
				p1[3] = SystemGetClkFreq(SYSTEM_CLK_APB2, SYSTEM_CLK_UNIT_MHZ);
				p1[4] = SystemGetClkFreq(SYSTEM_CLK_ADC, SYSTEM_CLK_UNIT_MHZ);
				p1[5] = SystemGetClkFreq(SYSTEM_CLK_USART0, SYSTEM_CLK_UNIT_MHZ);
				UartPrintf(UART_COM0, "SYS    FRE = %d\tMHz\r\n", p1[0]);
				UartPrintf(UART_COM0, "AHB    FRE = %d\tMHz\r\n", p1[1]);
				UartPrintf(UART_COM0, "APB1   FRE = %d\tMHz\r\n", p1[2]);
				UartPrintf(UART_COM0, "APB2   FRE = %d\tMHz\r\n", p1[3]);
				UartPrintf(UART_COM0, "ADC    FRE = %d\tMHz\r\n", p1[4]);
				UartPrintf(UART_COM0, "USART0 FRE = %d\tMHz\r\n", p1[3]);
				vPortFree(p1);
				
				taskEXIT_CRITICAL();
			}
		}
	}
}

static void cmdSystemCallback(CmdParamTypeDef *param)
{
	uint8_t *receive = UartGetRxBuffer(UART_COM0);
	
	/* system */
	if (param == NULL) {
		UartPutsDMA(UART_COM0, "OK\r\n");
		return;
	}
	
	/* system -name */
	if (strcmp(param->name, sParName) == 0) {
		UartPutsDMA(UART_COM0, "GD32E230F8P6TR\r\n");
	}
	/* system -version */
	else if (strcmp(param->name, sParVersion) == 0) {
	#ifdef USE_DEBUG_LOG
		UartPrintfDMA(UART_COM0, "V0.1 @branch: master with LOG\r\nbuild: %s\r\n", __DATE__);
	#else
		UartPrintfDMA(UART_COM0, "V0.1 @branch: master\r\nbuild: %s\r\n", __DATE__);
	#endif
	}
	else if (strcmp(param->name, sParGet) == 0) {
		parGetFunc(&receive[param->index], UartGetReceiveLen(UART_COM0) - param->index);
	}
	else {
		UartPutsDMA(UART_COM0, "system: No param\r\n");
	}
}

int8_t SystemCmdInit(void)
{
	int8_t result;
	
	result = CmdAppend(sCmdSystem, cmdSystemCallback);
	if (result != 0) {
		return 1;
	}
	
	result = CmdAppendParam(sCmdSystem, sParName);
	if (result != 0) {
		return 2;
	}
	
	result = CmdAppendParam(sCmdSystem, sParVersion);
	if (result != 0) {
		return 3;
	}
	
	result = CmdAppendParam(sCmdSystem, sParGet);
	if (result != 0) {
		return 4;
	}
	
	return 0;
}
